<template>
  <div class="chat-box im-container chat-content" @click="closeRefBox()" @mouseenter="readedMessage()">
    <el-container>
      <el-header height="60px" class="chat-header">
        <div class="header-left">
          <span class="chat-title">{{ title }}</span>
          <span class="member-count" v-show="isGroup">({{ memberSize }}人)</span>
        </div>
        <div class="header-right">
          <!-- 聊天记录按钮 -->
          <div class="header-btn" title="聊天记录" @click="showHistoryBox()">
            <i class="fas fa-history"></i>
          </div>
          <!-- 语音通话按钮 -->
          <div class="header-btn" v-show="isPrivate" title="语音通话" @click="showPrivateVideo('voice')">
            <i class="fas fa-phone"></i>
          </div>
          <div class="header-btn" v-show="isGroup" title="语音通话" @click="onGroupVideo()">
            <i class="fas fa-phone"></i>
          </div>
          <!-- 视频通话按钮 -->
          <div class="header-btn" v-show="isPrivate" title="视频通话" @click="showPrivateVideo('video')">
            <i class="fas fa-video"></i>
          </div>
          <!-- 群聊信息按钮 -->
          <div class="header-btn" v-show="isGroup" title="群聊信息" @click="showSide = !showSide">
            <i class="fas fa-info-circle"></i>
          </div>
        </div>
      </el-header>
      <el-main style="padding: 0">
        <el-container>
          <el-container class="content-box">
            <el-main class="im-chat-main" id="chatScrollBox" @scroll="onScroll">
              <div class="im-chat-box">
                <div v-for="(msgInfo, idx) in showMessages" :key="showMinIdx + idx">
                  <chat-message-item @call="onCall(msgInfo.type)" @voice-call="onVoiceCall" @video-call="onVideoCall"
                    :mine="msgInfo.sendId == mine.id" :headImage="headImage(msgInfo)" :showName="showName(msgInfo)"
                    :msgInfo="msgInfo" :groupMembers="groupMembers" @delete="deleteMessage" @recall="recallMessage"
                    @scroll-to-bottom="scrollToBottomForUserMessage">
                  </chat-message-item>
                </div>
              </div>
            </el-main>
            <div v-if="!isInBottom" class="scroll-to-bottom" :style="{ bottom: (inputAreaHeight + 20) + 'px' }"
              @click="scrollToBottom">
              {{
                newMessageSize > 0 ? newMessageSize + "条新消息" : "回到底部"
              }}
            </div>
            <el-footer :height="inputAreaHeight + 'px'" class="im-chat-footer">
              <!-- 垂直拉伸分隔器 -->
              <resizable-divider direction="vertical" :min-height="200" :max-height="300"
                @resize="handleInputAreaResize" />

              <div class="chat-tool-bar-container">
                <!-- 表情包组件放在工具栏容器内 -->
                <emotion ref="emoBox" @emotion="onEmotion" class="emotion-in-toolbar"></emotion>

                <div class="chat-tool-bar">
                  <div class="tool-btn" title="表情" ref="emotion" @click.stop="showEmotionBox()">
                    <i class="fas fa-smile"></i>
                  </div>
                  <div class="tool-btn" title="发送图片">
                    <file-upload action="image" :maxSize="5 * 1024 * 1024" :fileTypes="[
                      'image/jpeg',
                      'image/png',
                      'image/jpg',
                      'image/webp',
                      'image/gif',
                    ]" @before="onImageBefore" @success="onImageSuccess" @fail="onImageFail">
                      <i class="fas fa-image"></i>
                    </file-upload>
                  </div>
                  <div class="tool-btn" title="发送文件">
                    <file-upload ref="fileUpload" action="file" :maxSize="10 * 1024 * 1024" @before="onFileBefore"
                      @success="onFileSuccess" @fail="onFileFail">
                      <i class="fas fa-paperclip"></i>
                    </file-upload>
                  </div>
                  <div class="tool-btn" v-show="isGroup && memberSize <= 500" title="回执消息"
                    :class="isReceipt ? 'active' : ''" @click="onSwitchReceipt">
                    <i class="fas fa-check-double"></i>
                  </div>
                  <div class="tool-btn" title="发送语音" @click="showRecordBox()">
                    <i class="fas fa-microphone"></i>
                  </div>
                </div>
              </div>
              <div class="send-content-area" :style="{ height: inputContentHeight + 'px' }">
                <div class="input-container">
                  <ChatInput :ownerId="group.ownerId" ref="chatInputEditor" :group-members="groupMembers"
                    @submit="sendMessage" />
                </div>
                <div class="send-btn-area">
                  <el-button type="primary" icon="el-icon-s-promotion"
                             @click="notifySend()"
                             :disabled="isSending || isAISending">发送</el-button>
                </div>
              </div>
            </el-footer>
          </el-container>
          <el-aside class="side-box" width="320px" v-if="showSide">
            <chat-group-side :group="group" :groupMembers="groupMembers" @reload="loadGroup(group.id)">
            </chat-group-side>
          </el-aside>
        </el-container>
      </el-main>
      <chat-record :visible="showRecord" @close="closeRecordBox" @send="onSendRecord"></chat-record>
      <group-member-selector ref="rtcSel" :group="group" @complete="onInviteOk"></group-member-selector>
      <rtc-group-join ref="rtcJoin" :groupId="group.id"></rtc-group-join>
      <chat-history :visible="showHistory" :chat="chat" :friend="friend" :group="group" :groupMembers="groupMembers"
        @close="closeHistoryBox"></chat-history>
    </el-container>
  </div>
</template>

<script>
import ChatGroupSide from "./ChatGroupSide.vue";
import ChatMessageItem from "./ChatMessageItem.vue";
import FileUpload from "../common/FileUpload.vue";
import Emotion from "../common/Emotion.vue";
import ChatRecord from "./ChatRecord.vue";
import ChatHistory from "./ChatHistory.vue";
import ChatAtBox from "./ChatAtBox.vue";
import GroupMemberSelector from "../IMGroup/GroupMemberSelector.vue";
import RtcGroupJoin from "../IMRtc/RtcGroupJoin.vue";
import ChatInput from "./ChatInput.vue";
import ResizableDivider from "../common/ResizableDivider.vue";

// 导入统一的API接口
import { uploadImageApi, uploadFileApi, batchUploadImagesApi } from "@/api/imFile.js";
import { findUserByIdApi } from "@/api/imUser.js";
import { findGroupApi, getGroupMembersApi } from "@/api/imGroup.js";
import {
  sendPrivateMessageApi,
  sendGroupMessageApi,
  recallPrivateMessageApi,
  recallGroupMessageApi,
  readPrivateMessageApi,
  readGroupMessageApi,
  getMaxReadedIdApi,
} from "@/api/imMessage.js";
// 导入AI流式响应API
import aiStreamApi from "@/api/aiStream.js";

// 导入布局偏好设置工具
import { getChatInputAreaHeight, saveChatInputAreaHeight, debounce } from "@/utils/im/layoutPreferences.js";
// 导入头像缓存工具
import avatarCache from "@/utils/im/avatarCache.js";

export default {
  name: "chatPrivate",
  components: {
    ChatInput,
    ChatMessageItem,
    FileUpload,
    ChatGroupSide,
    Emotion,
    ChatRecord,
    ChatHistory,
    ChatAtBox,
    GroupMemberSelector,
    RtcGroupJoin,
    ResizableDivider,
  },
  props: {
    chat: {
      type: Object,
    },
  },
  data() {
    return {
      userInfo: {},
      group: {},
      groupMembers: [],
      sendImageUrl: "",
      sendImageFile: "",
      placeholder: "",
      isReceipt: true,
      showRecord: false, // 是否显示语音录制弹窗
      showSide: false, // 是否显示群聊信息栏
      showHistory: false, // 是否显示历史聊天记录
      lockMessage: false, // 是否锁定发送，
      showMinIdx: 0, // 下标低于showMinIdx的消息不显示，否则页面会很卡置
      reqQueue: [], // 等待发送的请求队列
      isSending: false, // 是否正在发消息
      isInBottom: false, // 滚动条是否在底部
      newMessageSize: 0, // 滚动条不在底部时新的消息数量
      inputAreaHeight: getChatInputAreaHeight(), // 输入区域高度，从本地存储恢复
      lastCallTime: 0, // 上次发起通话的时间
      callThrottle: 2000, // 2秒内防止重复发起通话
      // AI助手相关常量和状态（已移动到全局enums中）
      isAISending: false, // 是否正在发送AI消息，防止重复发送
      currentAIMessage: null, // 当前AI回复的消息对象
      lastMessageHash: null, // 上次发送消息的哈希值，用于防重复
      lastMessageTime: 0, // 上次发送消息的时间
    };
  },
  methods: {
    // 字符串哈希函数，用于生成请求唯一标识
    hashCode(str) {
      let hash = 0;
      if (str.length === 0) return hash;
      for (let i = 0; i < str.length; i++) {
        const char = str.charCodeAt(i);
        hash = ((hash << 5) - hash) + char;
        hash = hash & hash; // 转换为32位整数
      }
      return Math.abs(hash);
    },

    // 处理输入区域拉伸
    handleInputAreaResize(size) {
      if (size.height) {
        this.inputAreaHeight = size.height;
        // 防抖保存到本地存储
        this.debouncedSaveInputHeight(size.height);
      }
    },
    /**
     * 将当前聊天会话移动到顶部
     * @param {boolean} updateTime - 是否更新会话时间，默认true（发送消息时更新）
     */
    moveChatToTop(updateTime = true) {
      let chatIdx = this.chatStore.findChatIdx(this.chat);
      // 发送消息时需要更新时间，其他情况（如仅切换聊天）不更新
      this.chatStore.moveTop(chatIdx, updateTime);
    },
    closeRefBox() {
      this.$refs.emoBox.close();
      // this.$refs.atBox.close();
    },
    onCall(type) {
      if (type == this.$enums.MESSAGE_TYPE.ACT_RT_VOICE) {
        this.showPrivateVideo("voice");
      } else if (type == this.$enums.MESSAGE_TYPE.ACT_RT_VIDEO) {
        this.showPrivateVideo("video");
      }
    },

    // 处理语音通话重新呼叫
    onVoiceCall(msgInfo) {
      this.$message.info('正在发起语音通话...');
      this.showPrivateVideo("voice");
    },

    // 处理视频通话重新呼叫
    onVideoCall(msgInfo) {
      this.$message.info('正在发起视频通话...');
      this.showPrivateVideo("video");
    },
    onSwitchReceipt() {
      this.isReceipt = !this.isReceipt;
      this.refreshPlaceHolder();
    },
    onImageSuccess(data, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.content = JSON.stringify(data);
      msgInfo.receipt = this.isReceipt;
      this.sendMessageRequest(msgInfo).then((m) => {
        msgInfo.loadStatus = "ok";
        msgInfo.id = m.id;
        this.isReceipt = false;
        this.chatStore.insertMessage(msgInfo, file.chat);
        // 用户发送图片后流畅滚动到底部
        this.scrollToBottomForUserMessage();
      });
    },
    onImageFail(e, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.loadStatus = "fail";
      this.chatStore.insertMessage(msgInfo, file.chat);
    },
    onImageBefore(file) {
      // 被封禁提示
      if (this.isBanned) {
        this.showBannedTip();
        return;
      }
      let url = URL.createObjectURL(file);
      let data = {
        originUrl: url,
        thumbUrl: url,
      };
      let msgInfo = {
        id: 0,
        tmpId: this.generateId(),
        fileId: file.uid,
        sendId: this.mine.id,
        content: JSON.stringify(data),
        sendTime: new Date().getTime(),
        selfSend: true,
        type: 1,
        readedCount: 0,
        loadStatus: "loading",
        status: this.$enums.MESSAGE_STATUS.UNSEND,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      // 插入消息
      this.chatStore.insertMessage(msgInfo, this.chat);
      // 会话置顶
      this.moveChatToTop();
      // 用户发送图片时流畅滚动到底部
      this.scrollToBottomForUserMessage();
      // 借助file对象保存
      file.msgInfo = msgInfo;
      file.chat = this.chat;
    },
    onFileSuccess(url, file) {
      let data = {
        name: file.name,
        size: file.size,
        url: url,
      };
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.content = JSON.stringify(data);
      msgInfo.receipt = this.isReceipt;
      this.sendMessageRequest(msgInfo).then((m) => {
        msgInfo.loadStatus = "ok";
        msgInfo.id = m.id;
        this.isReceipt = false;
        this.refreshPlaceHolder();
        this.chatStore.insertMessage(msgInfo, file.chat);
        // 用户发送文件后流畅滚动到底部
        this.scrollToBottomForUserMessage();
      });
    },
    onFileFail(e, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.loadStatus = "fail";
      this.chatStore.insertMessage(msgInfo, file.chat);
    },
    onFileBefore(file) {
      // 被封禁提示
      if (this.isBanned) {
        this.showBannedTip();
        return;
      }
      let url = URL.createObjectURL(file);
      let data = {
        name: file.name,
        size: file.size,
        url: url,
      };
      let msgInfo = {
        id: 0,
        tmpId: this.generateId(),
        sendId: this.mine.id,
        content: JSON.stringify(data),
        sendTime: new Date().getTime(),
        selfSend: true,
        type: 2,
        loadStatus: "loading",
        readedCount: 0,
        status: this.$enums.MESSAGE_STATUS.UNSEND,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      // 插入消息
      this.chatStore.insertMessage(msgInfo, this.chat);
      // 会话置顶
      this.moveChatToTop();
      // 用户发送文件时流畅滚动到底部
      this.scrollToBottomForUserMessage();
      // 借助file对象透传
      file.msgInfo = msgInfo;
      file.chat = this.chat;
    },
    onCloseSide() {
      this.showSide = false;
    },
    onScrollToTop() {
      // 多展示10条信息
      this.showMinIdx = this.showMinIdx > 10 ? this.showMinIdx - 10 : 0;
    },
    onScroll(e) {
      let scrollElement = e.target;
      let scrollTop = scrollElement.scrollTop;
      if (scrollTop < 30) {
        // 在顶部,不滚动的情况
        // 多展示20条信息
        this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0;
        this.isInBottom = false;
      }
      // 滚到底部
      if (
        scrollTop + scrollElement.clientHeight >=
        scrollElement.scrollHeight - 30
      ) {
        this.isInBottom = true;
        this.newMessageSize = 0;
      }
    },
    showEmotionBox() {
      // 切换表情包显示状态
      if (this.$refs.emoBox.show) {
        this.$refs.emoBox.close();
      } else {
        this.$refs.emoBox.open();
      }
    },
    onEmotion(emoText) {
      this.$refs.chatInputEditor.insertEmoji(emoText);
    },
    showRecordBox() {
      this.showRecord = true;
    },
    closeRecordBox() {
      this.showRecord = false;
    },
    showPrivateVideo(mode) {
      // 检查是否被封禁
      if (this.isBanned) {
        this.showBannedTip();
        return;
      }

      // 防抖机制：防止用户快速点击导致重复发起通话
      const currentTime = Date.now();
      if (currentTime - this.lastCallTime < this.callThrottle) {
        console.log("通话请求过于频繁，已忽略");
        this.$message.warning("请勿频繁发起通话");
        return;
      }
      this.lastCallTime = currentTime;

      let rtcInfo = {
        mode: mode,
        isHost: true,
        friend: this.friend,
      };
      // 通过home.vue打开单人视频窗口
      console.log("发起通话请求:", mode, "目标用户:", this.friend.id);
      this.$eventBus.$emit("openPrivateVideo", rtcInfo);
    },
    onGroupVideo() {
      // 检查是否被封禁
      if (this.isBanned) {
        this.showBannedTip();
        return;
      }
      // 邀请成员发起通话
      let ids = [this.mine.id];
      let maxChannel = this.configStore.webrtc.maxChannel;
      this.$refs.rtcSel.open(maxChannel, ids, ids, []);
    },
    onInviteOk(members) {
      if (members.length < 2) {
        return;
      }
      let userInfos = [];
      members.forEach((m) => {
        userInfos.push({
          id: m.userId,
          nickName: m.showNickName,
          headImage: m.headImage,
          isCamera: false,
          isMicroPhone: true,
        });
      });
      let rtcInfo = {
        isHost: true,
        groupId: this.group.id,
        inviterId: this.mine.id,
        userInfos: userInfos,
      };
      // 通过home.vue打开多人视频窗口
      this.$eventBus.$emit("openGroupVideo", rtcInfo);
    },
    showHistoryBox() {
      this.showHistory = true;
    },
    closeHistoryBox() {
      this.showHistory = false;
    },
    onSendRecord(data) {
      // 检查是否被封禁
      if (this.isBanned) {
        this.showBannedTip();
        return;
      }
      let msgInfo = {
        content: JSON.stringify(data),
        type: 3,
        receipt: this.isReceipt,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      this.sendMessageRequest(msgInfo).then((m) => {
        m.selfSend = true;
        this.chatStore.insertMessage(m, this.chat);
        // 会话置顶
        this.moveChatToTop();
        // 保持输入框焦点
        this.$refs.chatInputEditor.focus();
        // 用户发送语音后流畅滚动到底部
        this.scrollToBottomForUserMessage();
        // 关闭录音窗口
        this.showRecord = false;
        this.isReceipt = false;
        this.refreshPlaceHolder();
      });
    },
    fillTargetId(msgInfo, targetId) {
      if (this.chat.type == "GROUP") {
        msgInfo.groupId = targetId;
      } else {
        msgInfo.recvId = targetId;
      }
    },
    notifySend() {
      this.$refs.chatInputEditor.submit();
    },
    onBeforeSubmit() {
      // 用户即将发送消息，设置标记
      this.userSendingMessage = true;
    },
    async sendMessage(fullList) {
      // 防重复提交：检查是否有相同内容正在处理
      const messageContent = fullList.map(item => item.content).join('');
      const messageHash = this.hashCode(messageContent);
      const now = Date.now();

      if (this.lastMessageHash === messageHash && (now - this.lastMessageTime) < 1000) {
        console.warn('检测到重复消息提交，忽略处理');
        return;
      }

      this.lastMessageHash = messageHash;
      this.lastMessageTime = now;

      this.resetEditor();
      this.readedMessage();
      // 检查是否被封禁
      if (this.isBanned) {
        this.showBannedTip();
        return;
      }

      let sendText = this.isReceipt ? "【回执消息】" : "";

      // 检查是否有混合消息（图片+文字）
      const mixedContent = this.buildMixedContent(fullList, sendText);
      if (mixedContent) {
        // 发送混合消息
        await this.sendMixedMessage(mixedContent);
      } else {
        // 顺序发送消息，确保消息顺序正确
        for (const msg of fullList) {
          switch (msg.type) {
            case "text":
              await this.sendTextMessage(sendText + msg.content, msg.atUserIds);
              break;
            case "image":
              await this.sendImageMessage(msg.content.file);
              break;
            case "file":
              await this.sendFileMessage(msg.content.file);
              break;
          }
        }
      }
    },
    sendImageMessage(file) {
      return new Promise((resolve, reject) => {
        this.onImageBefore(file);
        let formData = new FormData();
        formData.append("file", file);
        formData.append("isPermanent", true);
        uploadImageApi(formData)
          .then((res) => {
            this.onImageSuccess(res.data, file);
            resolve();
          })
          .catch((error) => {
            this.onImageFail(error, file);
            reject();
          });
        this.$nextTick(() => this.$refs.chatInputEditor.focus());
        // 用户发送图片时流畅滚动到底部
        this.scrollToBottomForUserMessage();
      });
    },
    sendTextMessage(sendText, atUserIds) {
      return new Promise((resolve, reject) => {
        if (!sendText.trim()) {
          reject();
        }

        // 检查是否是发给AI助手的私聊消息
        const isAIPrivateChat = this.chat.type === "PRIVATE" && this.chat.targetId === this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID;

        // 检查是否是群聊中@AI助手的消息
        const isAIGroupChat = this.chat.type === "GROUP" && sendText.includes("@小K");

        if (isAIPrivateChat || isAIGroupChat) {
          // 使用AI流式响应
          this.sendAIStreamMessage(sendText, atUserIds)
            .then(() => resolve())
            .catch((error) => reject(error));
          return;
        }

        let msgInfo = {
          content: sendText,
          type: 0,
        };
        // 填充对方id
        this.fillTargetId(msgInfo, this.chat.targetId);
        // 被@人员列表
        if (this.chat.type == "GROUP") {
          msgInfo.atUserIds = atUserIds;
          msgInfo.receipt = this.isReceipt;
        }
        this.lockMessage = true;
        this.sendMessageRequest(msgInfo)
          .then((m) => {
            m.selfSend = true;
            this.chatStore.insertMessage(m, this.chat);
            // 会话置顶
            this.moveChatToTop();
            // 用户发送文本消息后流畅滚动到底部
            this.scrollToBottomForUserMessage();
          })
          .finally(() => {
            // 解除锁定
            this.isReceipt = false;
            resolve();
          });
      });
    },

    /**
     * 发送AI流式响应消息
     * @param {string} content 消息内容
     * @returns {Promise} 发送结果
     */
    sendAIStreamMessage(content) {
      return new Promise(async (resolve, reject) => {
        // 简单防护：检查是否正在发送AI消息
        if (this.isAISending) {
          console.warn('AI消息正在发送中，忽略重复请求');
          reject(new Error('AI消息正在发送中，请稍候...'));
          return;
        }

        // 设置发送状态
        this.isAISending = true;

        try { // 发送AI流式消息
          // 1. 先发送用户消息到后端获取真实ID，避免刷新页面后重复消息
          const userMsgInfo = {
            content: content,
            type: 0,
            sendId: this.mine.id,
            sendNickName: this.mine.nickName,
            sendTime: new Date(),
            selfSend: true,
            status: this.$enums.MESSAGE_STATUS.SENDED // 设置为已发送状态
          };
          this.fillTargetId(userMsgInfo, this.chat.targetId);

          // 先发送到后端获取真实ID
          const savedUserMessage = await this.sendMessageRequest(userMsgInfo);
          // 使用后端返回的真实消息数据（包含真实ID）
          savedUserMessage.selfSend = true;
          this.chatStore.insertMessage(savedUserMessage, this.chat);
          this.scrollToBottomForUserMessage();

          // 2. 创建AI流式回复消息（包含思考和内容）
          const aiStreamMsgInfo = {
            id: 'ai_stream_' + Date.now(),
            content: '', // 初始为空，将通过流式更新
            thinkingContent: '', // 思考内容
            responseContent: '', // 回复内容
            type: 0,
            sendId: this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID,
            sendNickName: '小K',
            sendTime: new Date(),
            selfSend: false,
            isStreaming: true,
            streamType: 'thinking', // 初始状态为思考
            isAIStreamMessage: true // 标记为AI流式消息，用于区分WebSocket推送的消息
          };
          this.fillTargetId(aiStreamMsgInfo, this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID);
          this.chatStore.insertMessage(aiStreamMsgInfo, this.chat);
          this.scrollToBottomForUserMessage();

          // 保存当前AI消息引用
          this.currentAIMessage = aiStreamMsgInfo;

          // 3. 建立SSE连接进行流式响应，传递已创建的用户消息ID
          this.createAIStreamConnection(content, aiStreamMsgInfo, savedUserMessage.id)
            .then(() => resolve())
            .catch((error) => {
              this.isAISending = false; // 重置状态
              this.currentAIMessage = null; // 清理消息引用
              reject(error);
            });

        } catch (error) {
          console.error('发送AI流式消息失败:', error);
          this.isAISending = false; // 重置状态
          this.currentAIMessage = null; // 清理消息引用
          reject(error);
        }
      });
    },

    /**
     * 创建AI流式响应的SSE连接 - 统一消息版本
     * @param {string} content 用户输入内容
     * @param {Object} aiStreamMsgInfo AI流式消息对象
     * @param {number} userMessageId 已创建的用户消息ID
     * @returns {Promise} 连接结果
     */
    createAIStreamConnection(content, aiStreamMsgInfo, userMessageId) {
      return new Promise((resolve, reject) => {
        try {
          // 构建请求参数
          const requestData = {
            chatType: this.isGroup ? 'GROUP' : 'PRIVATE',
            receiverId: this.isGroup ? this.chat.targetId : this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID,
            senderId: this.mine.id,
            senderNickname: this.mine.nickName,
            content: content,
            sessionId: this.isGroup ? `group_${this.chat.targetId}_${this.mine.id}` : `private_${this.mine.id}_${this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID}`,
            userMessageId: userMessageId // 传递已创建的用户消息ID，避免后端重复创建
          };

          // 创建EventSource连接
          const eventSource = aiStreamApi.createStreamChat(requestData);

          let isCompleted = false; // 添加完成状态标记，防止重复处理
          let isUserMessageMarkedAsRead = false; // 标记用户消息是否已标记为已读，避免重复更新

          // 监听AI响应事件 - 修复事件名匹配问题
          eventSource.addEventListener('ai-response', (event) => {
            try {
              const data = JSON.parse(event.data);
              console.log('收到AI流式数据:', data);

              if (data.type === 'thinking') {
                // AI开始思考时，立即标记用户消息为已读（只执行一次）
                if (!isUserMessageMarkedAsRead) {
                  this.markUserMessageAsReadWithEventBus(userMessageId);
                  isUserMessageMarkedAsRead = true;
                  console.log('AI开始回复，用户消息已标记为已读，消息ID:', userMessageId);
                }

                // 流式追加思考内容，确保数据是字符串类型
                const thinkingData = typeof data.data === 'string' ? data.data : String(data.data || '');
                aiStreamMsgInfo.thinkingContent += thinkingData;
                aiStreamMsgInfo.content = aiStreamMsgInfo.thinkingContent;
                aiStreamMsgInfo.streamType = 'thinking';
                this.chatStore.updateMessage(aiStreamMsgInfo, this.chat);
                this.scrollToBottomForUserMessage();

              } else if (data.type === 'content') {
                // 切换到内容阶段，确保数据是字符串类型
                const contentData = typeof data.data === 'string' ? data.data : String(data.data || '');
                if (aiStreamMsgInfo.streamType === 'thinking') {
                  // 从思考阶段切换到内容阶段
                  aiStreamMsgInfo.streamType = 'content';
                  aiStreamMsgInfo.responseContent = contentData;
                  aiStreamMsgInfo.content = aiStreamMsgInfo.responseContent;
                } else {
                  // 继续追加内容
                  aiStreamMsgInfo.responseContent += contentData;
                  aiStreamMsgInfo.content = aiStreamMsgInfo.responseContent;
                }
                this.chatStore.updateMessage(aiStreamMsgInfo, this.chat);
                this.scrollToBottomForUserMessage();

              } else if (data.type === 'complete') {
                // 流式传输完成
                console.log('AI流式响应完成');

                if (isCompleted) {
                  console.log('AI流式响应已经完成，忽略重复complete事件');
                  return;
                }
                isCompleted = true; // 标记为已完成

                // 标记流式传输完成，构建完整的消息内容
                aiStreamMsgInfo.isStreaming = false;
                aiStreamMsgInfo.streamType = 'complete';

                // 构建完整的AI回复内容（包含思考过程），确保数据一致性
                if (aiStreamMsgInfo.thinkingContent && aiStreamMsgInfo.responseContent) {
                  if (this.chat.type === 'GROUP') {
                    // 群聊格式：@用户名\n\n📝 *思考过程*\n```\n思考内容\n```\n\n🤖 *回复*\n回复内容
                    aiStreamMsgInfo.content = `@${this.mine.nickName}\n\n📝 *思考过程*\n\`\`\`\n${aiStreamMsgInfo.thinkingContent}\n\`\`\`\n\n🤖 *回复*\n${aiStreamMsgInfo.responseContent}`;
                  } else {
                    // 私聊格式：📝 *思考过程*\n```\n思考内容\n```\n\n🤖 *回复*\n回复内容
                    aiStreamMsgInfo.content = `📝 *思考过程*\n\`\`\`\n${aiStreamMsgInfo.thinkingContent}\n\`\`\`\n\n🤖 *回复*\n${aiStreamMsgInfo.responseContent}`;
                  }
                } else if (aiStreamMsgInfo.responseContent) {
                  // 只有回复内容
                  if (this.chat.type === 'GROUP') {
                    aiStreamMsgInfo.content = `@${this.mine.nickName} ${aiStreamMsgInfo.responseContent}`;
                  } else {
                    aiStreamMsgInfo.content = aiStreamMsgInfo.responseContent;
                  }
                } else if (aiStreamMsgInfo.thinkingContent) {
                  // 只有思考内容
                  aiStreamMsgInfo.content = aiStreamMsgInfo.thinkingContent;
                }

                this.chatStore.updateMessage(aiStreamMsgInfo, this.chat);

                // 清理超时定时器
                if (eventSource._timeoutId) {
                  clearTimeout(eventSource._timeoutId);
                  eventSource._timeoutId = null;
                }

                // 移除错误监听器，防止close时触发error处理
                eventSource.onerror = null;

                // 重置状态
                this.isAISending = false;
                this.currentAIMessage = null;

                // 关闭连接
                eventSource.close();
                resolve();

              } else if (data.type === 'error') {
                // 处理错误
                console.error('AI流式响应错误:', data.error || data.message);

                if (isCompleted) {
                  console.log('AI流式响应已经完成，忽略后续error事件');
                  return;
                }
                isCompleted = true; // 标记为已完成

                this.handleAIStreamError(aiStreamMsgInfo, data.error || data.message);

                // 清理超时定时器
                if (eventSource._timeoutId) {
                  clearTimeout(eventSource._timeoutId);
                  eventSource._timeoutId = null;
                }

                // 重置状态
                this.isAISending = false;
                this.currentAIMessage = null;

                eventSource.close();
                reject(new Error(data.error || data.message));
              }

            } catch (parseError) {
              console.error('解析AI流式数据失败:', parseError);
            }
          });

          // 监听错误事件 - 优化版本，只处理真正的连接错误
          eventSource.onerror = (error) => {
            console.error('AI流式连接错误:', error);

            // 如果已经完成，忽略后续的error事件（这通常是正常关闭连接时触发的）
            if (isCompleted) {
              console.log('AI流式响应已经完成，忽略后续error事件');
              return;
            }

            // 只在连接状态为CLOSED且未正常完成时才处理为真正的错误
            if (eventSource.readyState === EventSource.CLOSED) {
              console.error('AI流式连接异常关闭，处理错误');
              isCompleted = true; // 标记为已完成

              this.handleAIStreamError(aiStreamMsgInfo, '连接AI服务失败，请稍后重试');

              // 清理超时定时器
              if (eventSource._timeoutId) {
                clearTimeout(eventSource._timeoutId);
                eventSource._timeoutId = null;
              }

              this.isAISending = false;
              this.currentAIMessage = null;
              reject(new Error('连接AI服务失败'));
            }
          };

          // 优化的超时处理（60秒，给AI更多时间思考）
          const timeoutId = setTimeout(() => {
            if (!isCompleted && eventSource.readyState !== EventSource.CLOSED) {
              console.warn('AI流式连接超时，强制关闭');
              isCompleted = true; // 标记为已完成

              this.handleAIStreamError(aiStreamMsgInfo, 'AI响应超时，请稍后重试');

              // 移除错误监听器，防止close时触发error处理
              eventSource.onerror = null;

              this.isAISending = false;
              this.currentAIMessage = null;
              eventSource.close();
              reject(new Error('连接超时'));
            }
          }, 60000); // 增加到60秒

          // 保存超时ID用于清理
          eventSource._timeoutId = timeoutId;

        } catch (error) {
          console.error('创建AI流式连接失败:', error);
          this.isAISending = false;
          this.currentAIMessage = null;
          reject(error);
        }
      });
    },

    /**
     * 处理AI流式响应错误 - 统一消息版本
     * @param {Object} aiStreamMsgInfo AI流式消息对象
     * @param {string} errorMessage 错误信息
     */
    handleAIStreamError(aiStreamMsgInfo, errorMessage) {
      try {
        // 更新AI流式消息为错误状态
        aiStreamMsgInfo.content = `❌ 抱歉，AI服务暂时不可用：${errorMessage}`;
        aiStreamMsgInfo.isStreaming = false;
        aiStreamMsgInfo.hasError = true;
        aiStreamMsgInfo.streamType = 'error';
        this.chatStore.updateMessage(aiStreamMsgInfo, this.chat);
        this.scrollToBottomForUserMessage();
      } catch (error) {
        console.error('处理AI流式响应错误时发生异常:', error);
      }
    },

    /**
     * 使用eventBus标记用户消息为已读状态（优雅的实时更新方案）
     * @param {number} userMessageId 用户消息ID
     */
    markUserMessageAsReadWithEventBus(userMessageId) {
      try {
        if (!userMessageId) {
          console.warn('用户消息ID为空，无法更新状态');
          return;
        }

        // 通过eventBus发送消息状态更新事件
        this.$eventBus.$emit('message-status-update', {
          messageId: userMessageId,
          status: this.$enums.MESSAGE_STATUS.READED
        });

        console.log('已通过eventBus发送消息状态更新事件，消息ID:', userMessageId, '状态: 已读');

        // 同时更新chatStore中的数据（保持数据一致性）
        this.updateChatStoreMessageStatus(userMessageId);

      } catch (error) {
        console.error('通过eventBus更新用户消息已读状态失败:', error);
      }
    },

    /**
     * 更新chatStore中的消息状态（保持数据一致性）
     * @param {number} userMessageId 用户消息ID
     */
    updateChatStoreMessageStatus(userMessageId) {
      try {
        const chat = this.chatStore.findChat(this.chat);
        if (!chat) {
          console.warn('未找到当前聊天，无法更新chatStore状态');
          return;
        }

        const userMessage = chat.messages.find(msg => msg.id === userMessageId);
        if (!userMessage) {
          console.warn('未找到指定ID的用户消息，ID:', userMessageId);
          return;
        }

        // 更新消息状态
        if (userMessage.selfSend && userMessage.status !== this.$enums.MESSAGE_STATUS.READED) {
          userMessage.status = this.$enums.MESSAGE_STATUS.READED;
          this.chatStore.updateMessage(userMessage, this.chat);
          console.log('chatStore中的消息状态已同步更新，消息ID:', userMessageId);
        }
      } catch (error) {
        console.error('更新chatStore消息状态失败:', error);
      }
    },

    sendFileMessage(file) {
      return new Promise((resolve, reject) => {
        let check = this.$refs.fileUpload.beforeUpload(file);
        if (check) {
          this.$refs.fileUpload.onFileUpload({ file });
        }
      });
    },
    // 构建混合消息内容 - 支持按顺序混合
    buildMixedContent(fullList, sendText) {
      let hasText = false;
      let hasImage = false;
      let items = [];
      let allAtUserIds = [];

      // 检查是否同时包含文字和图片，并按顺序构建items
      for (const msg of fullList) {
        if (msg.type === "text") {
          hasText = true;
          const content = (items.length === 0 && sendText) ? sendText + msg.content : msg.content;
          items.push({
            type: 'text',
            content: content
          });
          if (msg.atUserIds && msg.atUserIds.length > 0) {
            allAtUserIds = allAtUserIds.concat(msg.atUserIds);
          }
        } else if (msg.type === "image") {
          hasImage = true;
          items.push({
            type: 'image',
            file: msg.content.file,
            tempUrl: URL.createObjectURL(msg.content.file)
          });
        }
      }

      // 只有同时包含文字和图片才构建混合消息
      if (hasText && hasImage) {
        return {
          items: items,
          atUserIds: [...new Set(allAtUserIds)] // 去重
        };
      }
      return null;
    },
    // 发送混合消息 - 支持按顺序混合
    async sendMixedMessage(mixedContent) {
      try {
        // 被封禁提示
        if (this.isBanned) {
          this.showBannedTip();
          return;
        }

        // 构建临时消息内容项，保持用户输入顺序
        const tempItems = mixedContent.items.map(item => {
          if (item.type === 'text') {
            return {
              type: 'text',
              content: item.content
            };
          } else if (item.type === 'image') {
            return {
              type: 'image',
              content: item.tempUrl, // 临时URL
              thumbUrl: item.tempUrl,
              name: item.file.name,
              size: item.file.size
            };
          }
        });

        // 构建临时混合消息内容
        const tempContent = JSON.stringify({
          items: tempItems
        });

        // 参照onImageBefore的逻辑创建临时消息
        let msgInfo = {
          id: 0, // 临时ID为0，表示未发送到服务器
          tmpId: this.generateId(), // 生成唯一的临时ID，用于避免冲突
          sendId: this.mine.id,
          sendNickName: this.mine.nickName,
          sendAvatar: this.mine.avatar,
          content: tempContent,
          sendTime: new Date().getTime(),
          selfSend: true,
          type: 5, // 混合消息类型
          readedCount: 0,
          loadStatus: "loading", // 标记为加载中
          status: this.$enums.MESSAGE_STATUS.UNSEND,
        };

        // 填充对方id
        this.fillTargetId(msgInfo, this.chat.targetId);

        // 被@人员列表
        if (this.chat.type == "GROUP") {
          msgInfo.atUserIds = mixedContent.atUserIds;
          msgInfo.receipt = this.isReceipt;
        }

        // 先在本地显示消息（参照onImageBefore逻辑）
        this.chatStore.insertMessage(msgInfo, this.chat);

        // 会话置顶和滚动
        this.moveChatToTop();
        this.scrollToBottomForUserMessage();

        // 异步上传图片并更新消息
        this.uploadMixedMessageImages(msgInfo, mixedContent);

      } catch (error) {
        this.$message.error("发送混合消息失败：" + (error.message || "未知错误"));
        console.error("发送混合消息失败：", error);
      }
    },

    // 异步上传混合消息中的图片 - 支持按顺序混合
    async uploadMixedMessageImages(tempMsgInfo, mixedContent) {
      try {
        // 提取所有图片文件
        const imageFiles = mixedContent.items
          .filter(item => item.type === 'image')
          .map(item => item.file);

        // 使用批量上传API提高性能
        const formData = new FormData();
        imageFiles.forEach((file) => {
          formData.append("files", file);
        });
        formData.append("isPermanent", true);

        const res = await batchUploadImagesApi(formData);

        // 构建最终的消息内容项，保持顺序
        let imageIndex = 0;
        const finalItems = mixedContent.items.map(item => {
          if (item.type === 'text') {
            return {
              type: 'text',
              content: item.content
            };
          } else if (item.type === 'image') {
            const uploadedImage = res.data[imageIndex++];
            return {
              type: 'image',
              content: uploadedImage.originUrl,
              thumbUrl: uploadedImage.thumbUrl,
              originUrl: uploadedImage.originUrl,
              name: item.file.name,
              size: item.file.size
            };
          }
        });

        // 构建最终的混合消息内容
        const finalContent = JSON.stringify({
          items: finalItems
        });

        // 发送最终消息到服务器（参照onImageSuccess逻辑）
        let finalMsgInfo = JSON.parse(JSON.stringify(tempMsgInfo));
        finalMsgInfo.content = finalContent;
        finalMsgInfo.receipt = this.isReceipt;

        const result = await this.sendMessageRequest(finalMsgInfo);

        // 参照onImageSuccess的逻辑更新本地消息
        tempMsgInfo.loadStatus = "ok";
        tempMsgInfo.id = result.id;
        tempMsgInfo.content = finalContent;
        tempMsgInfo.sendTime = result.sendTime;
        tempMsgInfo.status = this.$enums.MESSAGE_STATUS.SENDED;

        // 清理临时URL
        mixedContent.items.forEach(item => {
          if (item.type === 'image' && item.tempUrl && item.tempUrl.startsWith('blob:')) {
            URL.revokeObjectURL(item.tempUrl);
          }
        });

      } catch (error) {
        // 参照onImageFail的逻辑处理失败
        tempMsgInfo.loadStatus = "fail";
        this.$message.error("图片上传失败，请重试");
        console.error("混合消息图片上传失败：", error);
      } finally {
        this.isReceipt = false;
        this.lockMessage = false;
      }
    },
    deleteMessage(msgInfo) {
      this.$confirm("确认删除消息?", "删除消息", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        this.chatStore.deleteMessage(msgInfo, this.chat);
      });
    },
    recallMessage(msgInfo) {
      this.$confirm("确认撤回消息?", "撤回消息", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        let recallPromise;
        if (this.chat.type === "PRIVATE") {
          recallPromise = recallPrivateMessageApi(msgInfo.id);
        } else {
          recallPromise = recallGroupMessageApi(msgInfo.id);
        }

        recallPromise
          .then((res) => {
            this.$message.success("消息已撤回");
            let m = res.data;
            m.selfSend = true;
            this.chatStore.recallMessage(m, this.chat);
          })
          .catch((error) => {
            this.$message.error("撤回失败：" + (error.message || "未知错误"));
          });
      });
    },
    readedMessage() {
      if (this.chat.unreadCount > 0) {
        if (this.isGroup) {
          readGroupMessageApi(this.chat.targetId)
            .then(() => {
              this.chatStore.resetUnreadCount(this.chat);
            })
            .catch((error) => {
              console.error("标记群消息已读失败：", error);
            });
        } else {
          // 特殊处理：AI助手不需要发送已读回执
          if (this.chat.targetId === this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID) {
            // 对于AI助手，只在本地重置未读数量，不发送已读回执
            this.chatStore.resetUnreadCount(this.chat);
            // 也不需要调用loadReaded，因为AI消息不需要已读状态管理
            return;
          }

          readPrivateMessageApi(this.chat.targetId)
            .then(() => {
              this.chatStore.resetUnreadCount(this.chat);
              this.loadReaded(this.chat.targetId);
            })
            .catch((error) => {
              console.error("标记私聊消息已读失败：", error);
            });
        }
      }
    },
    loadReaded(fId) {
      // 特殊处理：AI助手不需要已读状态管理
      if (fId === this.$enums.AI_ASSISTANT.XIAO_ASSISTANT_ID) {
        return;
      }

      getMaxReadedIdApi(fId)
        .then((res) => {
          this.chatStore.readedMessage({
            friendId: fId,
            maxId: res.data,
          });
        })
        .catch((error) => {
          console.error("获取私聊消息最大已读ID失败：", error);
        });
    },
    loadGroup(groupId) {
      findGroupApi(groupId)
        .then((res) => {
          this.group = res.data;
          this.chatStore.updateChatFromGroup(res.data);
          this.groupStore.updateGroup(res.data);
          // 预加载群组头像，指定类型为group
          if (res.data.headImage) {
            avatarCache.setAvatar(res.data.id, res.data.headImage, 'group');
            avatarCache.preloadAvatar(res.data.headImage);
          }
        })
        .catch((error) => {
          console.error("加载群组信息失败：", error);
        });

      getGroupMembersApi(groupId)
        .then((res) => {
          this.groupMembers = res.data;
          // 预加载群成员头像
          this.preloadGroupMemberAvatars(res.data);
        })
        .catch((error) => {
          console.error("加载群组成员失败：", error);
        });
    },
    updateFriendInfo() {
      if (this.isFriend) {
        // store的数据不能直接修改，深拷贝一份store的数据
        let friend = JSON.parse(JSON.stringify(this.friend));
        friend.headImage = this.userInfo.headImageThumb;
        friend.nickName = this.userInfo.nickName;
        friend.showNickName = friend.remarkNickName
          ? friend.remarkNickName
          : friend.nickName;
        this.chatStore.updateChatFromFriend(friend);
        this.friendStore.updateFriend(friend);
      } else {
        this.chatStore.updateChatFromUser(this.userInfo);
      }
    },
    loadFriend(friendId) {
      // 获取好友信息
      findUserByIdApi(friendId)
        .then((res) => {
          this.userInfo = res.data;
          this.updateFriendInfo();
          // 预加载好友头像，指定类型为user
          if (res.data.headImageThumb) {
            avatarCache.setAvatar(res.data.id, res.data.headImageThumb, 'user');
            avatarCache.preloadAvatar(res.data.headImageThumb);
          }
        })
        .catch((error) => {
          console.error("加载好友信息失败：", error);
        });
    },
    showName(msgInfo) {
      if (!msgInfo) {
        return "";
      }
      if (this.isGroup) {
        let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
        return member ? member.showNickName : msgInfo.sendNickName || "";
      } else {
        return msgInfo.selfSend ? this.mine.nickName : this.chat.showName;
      }
    },
    headImage(msgInfo) {
      if (this.isGroup) {
        let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
        if (member) {
          return member.headImage || member.headImageThumb || "";
        }
        // 如果群成员列表中没有找到，尝试从缓存获取用户头像
        const cachedAvatar = avatarCache.getAvatar(msgInfo.sendId, 'user');
        return cachedAvatar || "";
      } else {
        if (msgInfo.sendId == this.mine.id) {
          return this.mine.headImageThumb || "";
        } else {
          // 优先使用聊天对象的头像，然后尝试从缓存获取用户头像
          return this.chat.headImage || avatarCache.getAvatar(msgInfo.sendId, 'user') || "";
        }
      }
    },
    resetEditor() {
      this.$nextTick(() => {
        this.$refs.chatInputEditor.clear();
        this.$refs.chatInputEditor.focus();
      });
    },
    /**
     * 滚动到底部
     * @param {boolean} isUserSending - 是否为用户发送消息触发的滚动
     * @param {boolean} immediate - 是否立即滚动（无动画）
     */
    scrollToBottom(isUserSending = false, immediate = false) {
      const scrollElement = document.getElementById("chatScrollBox");
      if (!scrollElement) return;

      const scrollToEnd = () => {
        if (immediate || isUserSending) {
          // 用户发送消息时立即滚动，无动画
          scrollElement.scrollTop = scrollElement.scrollHeight;
          this.isInBottom = true;
          this.newMessageSize = 0;
        } else {
          // 其他情况使用平滑滚动
          scrollElement.scrollTo({
            top: scrollElement.scrollHeight,
            behavior: 'smooth'
          });
          // 延迟更新状态
          setTimeout(() => {
            this.isInBottom = true;
            this.newMessageSize = 0;
          }, 300);
        }
      };

      if (isUserSending) {
        // 用户发送消息时，等待DOM更新后立即滚动
        this.$nextTick(() => {
          // 再次确保DOM完全更新
          setTimeout(scrollToEnd, 0);
        });
      } else {
        // 其他情况正常滚动
        this.$nextTick(scrollToEnd);
      }
    },

    /**
     * 用户发送消息后的专用滚动方法
     * 确保流畅且无延迟的滚动体验
     */
    scrollToBottomForUserMessage() {
      // 使用多重 nextTick 确保消息完全渲染
      this.$nextTick(() => {
        this.$nextTick(() => {
          const scrollElement = document.getElementById("chatScrollBox");
          if (scrollElement) {
            // 立即滚动到底部，无动画
            scrollElement.scrollTop = scrollElement.scrollHeight;
            this.isInBottom = true;
            this.newMessageSize = 0;
          }
        });
      });
    },
    refreshPlaceHolder() {
      if (this.isReceipt) {
        this.placeholder = "【回执消息】";
      } else if (this.$refs.editBox && this.$refs.editBox.innerHTML) {
        this.placeholder = "";
      } else {
        this.placeholder = "聊点什么吧~";
      }
    },
    sendMessageRequest(msgInfo) {
      return new Promise((resolve, reject) => {
        // 请求入队列，防止请求"后发先至"，导致消息错序
        this.reqQueue.push({ msgInfo, resolve, reject });
        this.processReqQueue();
      });
    },
    processReqQueue() {
      if (this.reqQueue.length && !this.isSending) {
        this.isSending = true;
        const reqData = this.reqQueue.shift();

        // 根据聊天类型选择对应的API
        let sendPromise;
        if (this.chat.type === "PRIVATE") {
          sendPromise = sendPrivateMessageApi(reqData.msgInfo);
        } else {
          sendPromise = sendGroupMessageApi(reqData.msgInfo);
        }

        sendPromise
          .then((res) => {
            reqData.resolve(res.data);
          })
          .catch((e) => {
            reqData.reject(e);
          })
          .finally(() => {
            this.isSending = false;
            // 发送下一条请求
            this.processReqQueue();
          });
      }
    },
    showBannedTip() {
      let msgInfo = {
        tmpId: this.generateId(),
        sendId: this.mine.id,
        sendTime: new Date().getTime(),
        type: this.$enums.MESSAGE_TYPE.TIP_TEXT,
      };
      if (this.chat.type == "PRIVATE") {
        msgInfo.recvId = this.mine.id;
        msgInfo.content = "该用户已被管理员封禁,原因:" + this.userInfo.reason;
      } else {
        msgInfo.groupId = this.group.id;
        msgInfo.content = "本群聊已被管理员封禁,原因:" + this.group.reason;
      }
      this.chatStore.insertMessage(msgInfo, this.chat);
    },
    generateId() {
      // 生成临时id
      return (
        String(new Date().getTime()) + String(Math.floor(Math.random() * 1000))
      );
    },

    /**
     * 预加载群成员头像
     */
    async preloadGroupMemberAvatars(members) {
      if (!Array.isArray(members) || members.length === 0) return;

      try {
        // 批量设置用户头像缓存
        avatarCache.batchSetAvatars(members, 'user');

        // 提取头像URL并预加载
        const avatarUrls = members
          .map(member => member.headImage || member.headImageThumb)
          .filter(url => url && typeof url === 'string');

        if (avatarUrls.length > 0) {
          await avatarCache.batchPreloadAvatars(avatarUrls);
          console.log(`群成员头像预加载完成，共 ${avatarUrls.length} 个头像`);
        }
      } catch (error) {
        console.warn('群成员头像预加载失败:', error);
      }
    },

    /**
     * 预加载聊天消息中的头像
     */
    async preloadChatMessageAvatars() {
      if (!this.chat || !this.chat.messages) return;

      try {
        // 提取消息中的发送者ID
        const senderIds = [...new Set(
          this.chat.messages
            .filter(msg => msg.sendId && msg.sendId !== this.mine.id)
            .map(msg => msg.sendId)
        )];

        // 如果是群聊，从群成员中获取头像
        if (this.isGroup && this.groupMembers.length > 0) {
          const senderAvatars = senderIds
            .map(senderId => {
              const member = this.groupMembers.find(m => m.userId === senderId);
              return member ? {
                userId: senderId,
                headImage: member.headImage || member.headImageThumb
              } : null;
            })
            .filter(item => item && item.headImage);

          if (senderAvatars.length > 0) {
            avatarCache.batchSetAvatars(senderAvatars, 'user');
            const urls = senderAvatars.map(item => item.headImage);
            await avatarCache.batchPreloadAvatars(urls);
          }
        }
      } catch (error) {
        console.warn('聊天消息头像预加载失败:', error);
      }
    },
  },
  computed: {
    mine() {
      return this.userStore.userInfo;
    },
    isFriend() {
      return this.friendStore.isFriend(this.userInfo.id);
    },
    friend() {
      return this.friendStore.findFriend(this.userInfo.id);
    },
    title() {
      let title = this.chat.showName;
      if (this.chat.type == "GROUP") {
        let size = this.groupMembers.filter((m) => !m.quit).length;
        title += `(${size})`;
      }
      return title;
    },

    unreadCount() {
      return this.chat.unreadCount;
    },
    showMessages() {
      return this.chat.messages.slice(this.showMinIdx);
    },
    messageSize() {
      if (!this.chat || !this.chat.messages) {
        return 0;
      }
      return this.chat.messages.length;
    },
    isBanned() {
      return (
        (this.chat.type == "PRIVATE" && this.userInfo.isBanned) ||
        (this.chat.type == "GROUP" && this.group.isBanned)
      );
    },
    memberSize() {
      return this.groupMembers.filter((m) => !m.quit).length;
    },
    isGroup() {
      return this.chat.type == "GROUP";
    },
    isPrivate() {
      return this.chat.type == "PRIVATE";
    },
    // 计算输入内容区域的高度（总高度减去工具栏高度）
    inputContentHeight() {
      return this.inputAreaHeight - 40; // 40px是工具栏的高度
    },
  },
  watch: {
    chat: {
      handler(newChat, oldChat) {
        if (
          newChat.targetId > 0 &&
          (!oldChat ||
            newChat.type != oldChat.type ||
            newChat.targetId != oldChat.targetId)
        ) {
          this.userInfo = {};
          this.group = {};
          this.groupMembers = [];
          if (this.chat.type == "GROUP") {
            this.loadGroup(this.chat.targetId);
          } else {
            this.loadFriend(this.chat.targetId);
            // 加载已读状态（AI助手除外）
            this.loadReaded(this.chat.targetId);
          }
          // 滚到底部
          this.scrollToBottom();
          this.showSide = false;
          // 消息已读
          this.readedMessage();
          // 初始状态只显示30条消息
          let size = this.chat.messages.length;
          this.showMinIdx = size > 30 ? size - 30 : 0;
          // 重置输入框
          this.resetEditor();
          // 复位回执消息
          this.isReceipt = false;
          // 更新placeholder
          this.refreshPlaceHolder();
          // 预加载聊天消息中的头像
          this.$nextTick(() => {
            this.preloadChatMessageAvatars();
          });
        }
      },
      immediate: true,
    },
    messageSize: {
      handler(newSize, oldSize) {
        if (newSize > oldSize) {
          // 获取最新的消息
          const messages = this.chat?.messages || [];
          const latestMessage = messages[messages.length - 1];

          // 检查最新消息是否是用户自己发送的
          const isUserMessage = latestMessage && latestMessage.selfSend;

          if (isUserMessage) {
            // 用户自己发送的消息，不在这里处理滚动
            // 滚动已在发送消息的方法中处理
            return;
          }

          // 别人发送的消息处理
          if (this.isInBottom) {
            // 如果滚动条在底部，平滑滚动到底部
            this.scrollToBottom(false, false);
          } else {
            // 增加新消息提醒
            this.newMessageSize++;
          }
        }
      },
    },
  },
  mounted() {
    let div = document.getElementById("chatScrollBox");
    div.addEventListener("scroll", this.onScroll);

    // 初始化防抖保存函数
    this.debouncedSaveInputHeight = debounce((height) => {
      saveChatInputAreaHeight(height);
    }, 300);
  },

  beforeDestroy() {
    // 清理AI流式连接 - 简化版本
    try {
      aiStreamApi.forceCloseCurrentConnection();
    } catch (error) {
      console.error('清理AI流式连接失败:', error);
    }

    // 重置AI发送状态
    this.isAISending = false;
    this.currentAIMessage = null;
  },
};
</script>

<style lang="scss" scoped>
@use "@/styles/variables.scss" as *;

.chat-box {
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--im-bg-primary);

  .el-container {
    height: 100%;
  }

  // === 聊天头部样式 ===
  .chat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: var(--im-border);
    background: var(--im-bg-primary);
    padding: 0 var(--im-spacing-xl);
    box-shadow: var(--im-box-shadow-sm);

    .header-left {
      display: flex;
      align-items: center;
      gap: var(--im-spacing-sm);

      .chat-title {
        font-size: var(--im-font-size-lg);
        font-weight: 600;
        color: var(--im-text-color-primary);
      }

      .member-count {
        font-size: var(--im-font-size-sm);
        color: var(--im-text-color-secondary);
        background: var(--im-bg-secondary);
        padding: 2px var(--im-spacing-sm);
        border-radius: var(--im-border-radius-round);
      }
    }

    .header-right {
      display: flex;
      align-items: center;
      gap: var(--im-spacing-sm);

      .header-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        border-radius: var(--im-border-radius-base);
        cursor: pointer;
        color: var(--im-text-color-secondary);
        transition: all var(--im-transition-base);
        background: transparent;

        &:hover {
          background: var(--im-bg-hover);
          color: var(--im-color-primary);
          transform: scale(1.05);
        }

        &:active {
          transform: scale(0.95);
        }

        i {
          font-size: 16px;
        }
      }
    }
  }

  // === 聊天内容区域 ===
  .content-box {
    position: relative;
    height: 100%;
    background: var(--im-bg-primary);

    .im-chat-main {
      padding: 0;
      background: var(--im-bg-primary);
      overflow-y: auto;
      overflow-x: visible; // 允许头像完全显示

      // 兼容 Firefox
      scrollbar-width: thin;
      scrollbar-color: var(--im-color-primary-light-6) transparent;

      .im-chat-box {
        padding: var(--im-spacing-base) 0; // 移除左右内边距，让消息项自己控制边距
        width: 100%;
        max-width: 100%;
        margin: 0;
        display: flex;
        flex-direction: column;

        >ul {
          padding: 0;
          margin: 0;
          width: 100%;
          list-style: none;

          li {
            list-style-type: none;
            width: 100%;
          }
        }

        // 确保消息项占满宽度
        >div {
          width: 100%;
        }
      }
    }

    // 回到底部按钮 - 动态定位到输入工具栏上方
    .scroll-to-bottom {
      position: absolute;
      right: var(--im-spacing-xl);
      /* bottom值通过内联样式动态设置 */
      background: var(--im-color-primary);
      color: white;
      font-size: var(--im-font-size-sm);
      font-weight: 500;
      padding: var(--im-spacing-sm) var(--im-spacing-lg);
      border-radius: var(--im-border-radius-round);
      cursor: pointer;
      z-index: 100;
      box-shadow: var(--im-box-shadow-base);
      transition: all var(--im-transition-base);
      text-align: center;

      &:hover {
        background: var(--im-color-primary-dark-1);
        transform: translateY(-2px);
        box-shadow: var(--im-box-shadow-lg);
      }

      &:active {
        transform: translateY(0);
      }
    }

    // === 聊天输入区域 ===
    .im-chat-footer {
      display: flex;
      flex-direction: column;
      border-top: var(--im-border);
      background: var(--im-bg-primary);
      /* 确保footer有正确的高度和布局 */
      position: relative;

      /* 拉伸分隔器样式 - 放在工具栏上方 */
      :deep(.resizable-divider) {
        position: absolute;
        top: -4px;
        left: 0;
        right: 0;
        height: 8px;
        cursor: ns-resize;
        z-index: 10;

        &.vertical {
          top: -4px;
          bottom: auto;
        }
      }

      .chat-tool-bar-container {
        position: relative;

        .emotion-in-toolbar {
          position: absolute;
          bottom: 100%;
          left: 0;
          z-index: 1000;
        }
      }

      .chat-tool-bar {
        display: flex;
        align-items: center;
        gap: var(--im-spacing-sm);
        padding: var(--im-spacing-base) var(--im-spacing-lg);
        border-bottom: var(--im-border-light);
        /* 固定工具栏高度为40px */
        height: 40px;
        flex-shrink: 0;

        .tool-btn {
          display: flex;
          align-items: center;
          justify-content: center;
          width: 32px;
          height: 32px;
          border-radius: var(--im-border-radius-base);
          cursor: pointer;
          color: var(--im-text-color-secondary);
          transition: all var(--im-transition-base);
          background: transparent;

          &:hover {
            background: var(--im-bg-hover);
            color: var(--im-color-primary);
            transform: scale(1.1);
          }

          &:active {
            transform: scale(0.95);
          }

          &.active {
            background: var(--im-bg-active);
            color: var(--im-color-primary);
          }

          i {
            font-size: 16px;
          }
        }
      }

      .send-content-area {
        display: flex;
        flex-direction: row;
        align-items: flex-end;
        gap: var(--im-spacing-base);
        padding: var(--im-spacing-base) var(--im-spacing-lg);
        background: var(--im-bg-primary);
        min-height: 80px;
        /* 使用动态高度，允许拉伸 */
        flex: 1;

        .input-container {
          flex: 1;
          min-height: 60px;
          /* 移除最大高度限制，让它可以随着父容器拉伸 */
          height: calc(100% - 20px);
          /* 减去padding */
          border: var(--im-border);
          border-radius: var(--im-border-radius-lg);
          background: var(--im-bg-secondary);
          overflow: hidden;

          :deep(.chat-input-area) {
            height: 100%;
            min-height: 60px;

            .edit-chat-container {
              height: 100%;
              min-height: 60px;
              /* 移除最大高度限制，让它可以随着父容器拉伸 */
              overflow-y: auto;
              padding: var(--im-spacing-base);
              border: none;
              background: transparent;
              resize: none;
              outline: none;
              font-size: var(--im-font-size-base);
              line-height: 1.5;
              color: var(--im-text-color-primary);

              &:focus {
                outline: none;
              }
            }
          }
        }

        .send-btn-area {
          display: flex;
          align-items: center;
          margin-bottom: 4px;

          .el-button {
            border-radius: var(--im-border-radius-base) !important;
            font-weight: 500 !important;
            padding: var(--im-spacing-base) var(--im-spacing-xl) !important;
            transition: all var(--im-transition-base) !important;
            height: 36px !important;

            &:hover {
              transform: translateY(-1px) !important;
              box-shadow: var(--im-box-shadow-hover) !important;
            }

            &:active {
              transform: translateY(0) !important;
            }
          }
        }
      }
    }
  }

  // === 侧边栏样式 ===
  .side-box {
    border-left: var(--im-border);
    background: var(--im-bg-secondary);
    box-shadow: var(--im-box-shadow-sm);
  }
}

// === 深色模式适配 ===
:root[data-theme="dark"] {
  .chat-box {
    background: var(--im-bg-primary);

    .chat-header {
      background: var(--im-bg-tertiary);
      border-bottom-color: var(--im-border-color);
    }

    .content-box {
      background: var(--im-bg-primary);

      .im-chat-main {
        background: var(--im-bg-primary);
      }
    }

    .im-chat-footer {
      background: var(--im-bg-tertiary);
      border-top-color: var(--im-border-color);

      .chat-tool-bar {
        border-bottom-color: var(--im-border-color);
      }

      .send-content-area {
        background: var(--im-bg-tertiary);

        .send-btn-area {
          background: var(--im-bg-tertiary);
        }
      }
    }

    .side-box {
      background: var(--im-bg-tertiary);
      border-left-color: var(--im-border-color);
    }
  }
}
</style>
